﻿////////////////////////////////////////////////////////////////////////////
//
//  Immense Engine Source File.
//  Copyright (C), Indloon 2012
// -------------------------------------------------------------------------
//  File name:   ieMathColor.h
//  Description: A ieColor class
//  Created:     08/12/2012 Genert Org
//  Compilers:   Visual C++ 2010 Express
// -------------------------------------------------------------------------
//  History:
//
////////////////////////////////////////////////////////////////////////////
#ifndef __IMMENSEENGINE_MATH_IECOLOR_H
#define __IMMENSEENGINE_MATH_IECOLOR_H
#pragma once

/*  1. C L A S S  &  E X T E R N S  &  D E F I N E S
	=========================================================================== */

const int C_COLOR_ESCAPE			= '^';
const int C_COLOR_DEFAULT			= '0';
const int C_COLOR_RED				= '1';
const int C_COLOR_GREEN				= '2';
const int C_COLOR_YELLOW			= '3';
const int C_COLOR_BLUE				= '4';
const int C_COLOR_CYAN				= '5';
const int C_COLOR_MAGENTA			= '6';
const int C_COLOR_WHITE				= '7';
const int C_COLOR_GRAY				= '8';
const int C_COLOR_BLACK				= '9';

#define S_COLOR_DEFAULT				"^0"
#define S_COLOR_RED					"^1"
#define S_COLOR_GREEN				"^2"
#define S_COLOR_YELLOW				"^3"
#define S_COLOR_BLUE				"^4"
#define S_COLOR_CYAN				"^5"
#define S_COLOR_MAGENTA				"^6"
#define S_COLOR_WHITE				"^7"
#define S_COLOR_GRAY				"^8"
#define S_COLOR_BLACK				"^9"

#define COLOR_MASK					63
#define COLOR_DEFAULT				52
#define COLOR_BLACK					0
#define COLOR_RED					1
#define COLOR_GREEN					2
#define COLOR_BLUE					3
#define COLOR_YELLOW				4
#define COLOR_CYAN					5
#define COLOR_MAGENTA				6
#define COLOR_WHITE					7

extern ieVec4		ColorBlack;
extern ieVec4		ColorRed;
extern ieVec4		ColorGreen;
extern ieVec4		ColorBlue;
extern ieVec4		ColorYellow;
extern ieVec4		ColorCyan;
extern ieVec4		ColorMagenta;
extern ieVec4		ColorWhite;
extern ieVec4		ColorOrange;
extern ieVec4		ColorChartreuse;
extern ieVec4		ColorSpringGreen;
extern ieVec4		ColorAzure;
extern ieVec4		ColorViolet;
extern ieVec4		ColorRose;
extern ieVec4		ColorGray;

extern ieVec4       Color_table[64];

#if defined (NEED_ENDIAN_SWAP)
	#define RGBA8(a,b,g,r)     ((uint32)(((uint8)(r)|((uint16)((uint8)(g))<<8))|(((uint32)(uint8)(b))<<16)) | (((uint32)(uint8)(a))<<24) )
#else
	#define RGBA8(r,g,b,a)     ((uint32)(((uint8)(r)|((uint16)((uint8)(g))<<8))|(((uint32)(uint8)(b))<<16)) | (((uint32)(uint8)(a))<<24) )
#endif

class ieColor {
private:
    byte r;
	byte g;
	byte b;
	byte a;
	
public:
    				ieColor( void );
	explicit		ieColor( const byte value );
	explicit		ieColor( const byte value, const byte a );
	explicit		ieColor( const byte r, const byte g, const byte b );
	explicit		ieColor( const byte r, const byte g, const byte b, const byte a );
	
    byte			operator [] ( const int index ) const;
	byte &			operator [] ( const int index );
	ieColor &		operator = ( const ieColor &color );
	bool			operator == ( const ieColor &color ) const;
	bool			operator != ( const ieColor &color ) const;
	ieColor			operator + ( const ieColor &color ) const;
	ieColor			operator - ( const ieColor &color ) const;
	ieColor			operator * ( const ieColor &color ) const;
	ieColor &		operator += ( const ieColor &color );
	ieColor &		operator -= ( const ieColor &color );
	ieColor &		operator *= ( const ieColor &color );

	void			Set( const byte l);
	void			Set( const byte l, const byte a );
	void			Set( const byte r, const byte g, const byte b );
	void			Set( const byte r, const byte g, const byte b, const byte a );
	void			Zero( void );
	void            Clear( void );
	bool			IsZeroed( void ) const;
	bool            IsCleared( void ) const;
	void			Identity( void );
	bool			IsIdentity( void ) const;
	void            Blend( const ieColor &src, const ieColor &dst, const float frac );
	const byte     *ToBytePtr (void ) const;
	byte           *ToBytePtr( void );
	void			Pack( const float l );
	void			Pack( const float l, const float a );
	void			Pack( const float r, const float g, const float b );
	void			Pack( const float r, const float g, const float b, const float a );
	void			Pack( const ieVec3 &rgb );
	void			Pack( const ieVec4 &rgba );
	void			Unpack( float &l ) const;
	void			Unpack( float &l, float &a ) const;
	void			Unpack( float &r, float &g, float &b ) const;
	void			Unpack( float &r, float &g, float &b, float &a ) const;
	void			Unpack( ieVec3 &rgb ) const;
	void			Unpack( ieVec4 &rgba ) const;

};
	
/*  2. F U N C T I O N S
	=========================================================================== */
	
// -------------------------------------------------------------------------------------------------------------
ILINE ieColor::ieColor( void )
{
    // ...
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieColor::ieColor( const byte value )
{
    this->r = value;
	this->g = value;
	this->b = value;
	this->a = 255;
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieColor::ieColor( const byte value, const byte a )
{
    this->r = value;
	this->g = value;
	this->b = value;
	this->a = a;
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieColor::ieColor(  const byte r, const byte g, const byte b )
{
    this->r = r;
	this->g = g;
	this->b = b;
	this->a = 255;
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieColor::ieColor( const byte r, const byte g, const byte b, const byte a )
{
    this->r = r;
	this->g = g;
	this->b = b;
	this->a = a;
}
// -------------------------------------------------------------------------------------------------------------
ILINE byte ieColor::operator [] ( const int index ) const 
{
	return ( &r )[index];
}
// -------------------------------------------------------------------------------------------------------------
ILINE byte &ieColor::operator [] ( const int index )
{
	return ( &r )[index];
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieColor &ieColor::operator = ( const ieColor &ieColor )
{
	r = ieColor.r;
	g = ieColor.g;
	b = ieColor.b;
	a = ieColor.a;
}
// -------------------------------------------------------------------------------------------------------------
ILINE bool ieColor::operator == ( const ieColor &color ) const
{
	if( ( r != color.r ) || ( g != color.g ) || ( b != color.b ) || ( a != color.a ) )
	{
        return false;
	}
	else
	{
		return true;
	}
}
// -------------------------------------------------------------------------------------------------------------
ILINE bool ieColor::operator != ( const ieColor &color ) const
{
	if( ( r != color.r ) || ( g != color.g ) || ( b != color.b ) || ( a != color.a ) )
	{
		return true;
	}
	else
	{
		return false;
	}
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieColor ieColor::operator + ( const ieColor &color ) const
{
	ieColor result;

	result.r = Min( r + color.r, 255 );
	result.g = Min( g + color.g, 255 );
	result.b = Min( b + color.b, 255 );
	result.a = Min( a + color.a, 255 );

	return result;
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieColor ieColor::operator - ( const ieColor &color ) const
{
	ieColor result;

	result.r = Max( r - color.r, 0 );
	result.g = Max( g - color.g, 0 );
	result.b = Max( b - color.b, 0 );
	result.a = Max( a - color.a, 0 );

	return result;
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieColor ieColor::operator * ( const ieColor &color ) const
{
    ieColor	result;

	result.r = ieMath::FloatToByte( r * ( color.r * ( 1.0f / 255.0f ) ) );
	result.g = ieMath::FloatToByte( g * ( color.g * ( 1.0f / 255.0f ) ) );
	result.b = ieMath::FloatToByte( b * ( color.b * ( 1.0f / 255.0f ) ) );
	result.a = ieMath::FloatToByte( a * ( color.a * ( 1.0f / 255.0f ) ) );

	return result;
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieColor &ieColor::operator += ( const ieColor &color )
{
    r = Min( r + color.r, 255 );
	g = Min( g + color.g, 255 );
	b = Min( b + color.b, 255 );
	a = Min( a + color.a, 255 );

	return *this;
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieColor &ieColor::operator -= ( const ieColor &color )
{
    r = Max( r - color.r, 0 );
	g = Max( g - color.g, 0 );
	b = Max( b - color.b, 0 );
	a = Max( a - color.a, 0 );

	return *this;
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieColor &ieColor::operator *= ( const ieColor &color )
{
    r = ieMath::FloatToByte( r * ( color.r * ( 1.0f / 255.0f ) ) );
	g = ieMath::FloatToByte( g * ( color.g * ( 1.0f / 255.0f ) ) );
	b = ieMath::FloatToByte( b * ( color.b * ( 1.0f / 255.0f ) ) );
	a = ieMath::FloatToByte( a * ( color.a * ( 1.0f / 255.0f ) ) );

	return *this;
}
// -------------------------------------------------------------------------------------------------------------
ILINE void ieColor::Set( const byte l )
{
	this->r = l;
	this->g = l;
	this->b = l;
	this->a = 255;
}
// -------------------------------------------------------------------------------------------------------------
ILINE void ieColor::Set( const byte l, const byte a )
{
    this->r = l;
    this->g = l;
    this->b = l;
    this->a = a;
}
// -------------------------------------------------------------------------------------------------------------
ILINE void ieColor::Set( const byte r, const byte g, const byte b ) 
{
    this->r = r;
    this->g = g;
    this->b = b;
    this->a = 255;
}
// -------------------------------------------------------------------------------------------------------------
ILINE void ieColor::Set( const byte r, const byte g, const byte b, const byte a )
{
	this->r = r;
	this->g = g;
	this->b = b;
	this->a = a;
}
// -------------------------------------------------------------------------------------------------------------
ILINE void ieColor::Zero( void )
{
    r = g = b = a = 0;
}
// -------------------------------------------------------------------------------------------------------------
ILINE void ieColor::Clear( void )
{
    r = g = b = a = 0;
}
// -------------------------------------------------------------------------------------------------------------
ILINE bool ieColor::IsZeroed( void ) const
{
    if ( ( r != 0 ) || ( b != 0 ) || ( g != 0 ) || ( a != 0 ) )
    {
    	return false;
    }
    else 
    {
    	return true;
    }
}
// -------------------------------------------------------------------------------------------------------------
ILINE bool ieColor::IsCleared( void ) const
{
    if( ( r == 0 ) && ( b == 0 ) && ( g == 0 ) && ( a == 0 ) )
    {
    	return true;
    }
    else
    {
    	return false;
    }
}
// -------------------------------------------------------------------------------------------------------------
ILINE void ieColor::Identity( void )
{
	r = 255;
	g = 255;
	b = 255;
	a = 255;
}
// -------------------------------------------------------------------------------------------------------------
ILINE bool ieColor::IsIdentity( void ) const
{
    if ( ( r != 255 ) || ( g != 255 ) || ( b != 255 ) || ( a != 255 ) )
    {
		return false;
	}
	else
	{
        return true;
	}
}
// -------------------------------------------------------------------------------------------------------------
ILINE void ieColor::Blend( const ieColor &src, const ieColor &dst, const float frac )
{
	int		scale, invScale;

	scale = ieMath::FloatToInt( 256.0f * frac );
	invScale = 256 - scale;

	r = ( src.r * invScale + dst.r * scale ) >> 8;
	g = ( src.g * invScale + dst.g * scale ) >> 8;
	b = ( src.b * invScale + dst.b * scale ) >> 8;
	a = ( src.a * invScale + dst.a * scale ) >> 8;
}
// -------------------------------------------------------------------------------------------------------------
ILINE const byte *ieColor::ToBytePtr (void ) const 
{
	return &r;
}
// -------------------------------------------------------------------------------------------------------------
ILINE byte *ieColor::ToBytePtr( void )
{
	return &r;
}
// -------------------------------------------------------------------------------------------------------------


#endif // __IMMENSEENGINE_MATH_IECOLOR_H